home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src.arc / FTPSERV.C < prev    next >
C/C++ Source or Header  |  1989-08-19  |  16KB  |  681 lines

  1. /* FTP Server state machine - see RFC 959 */
  2. #include <stdio.h>
  3. #include <ctype.h>
  4. #include <time.h>
  5. #include <io.h>
  6. #include <dir.h>
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "socket.h"
  10. #include "ftp.h"
  11. #include "ftpserv.h"
  12. #include "proc.h"
  13. #include "dirutil.h"
  14.  
  15. static void ftpserv __ARGS((int s,void *unused,void *p));
  16. static int pport __ARGS((struct sockaddr_in *sock,char *arg));
  17. static void ftplogin __ARGS((struct ftpserv *ftp,char *pass));
  18. static int sendit __ARGS((struct ftpserv *ftp,char *command,char *file));
  19. static int recvit __ARGS((struct ftpserv *ftp,char *command,char *file));
  20. static int permcheck __ARGS((struct ftpserv *ftp,int op,char *file));
  21.  
  22. extern char Hostname[],Version[];
  23.  
  24. /* Command table */
  25. static char *commands[] = {
  26.     "user",
  27. #define    USER_CMD    0
  28.     "acct",
  29. #define    ACCT_CMD    1
  30.     "pass",
  31. #define    PASS_CMD    2
  32.     "type",
  33. #define    TYPE_CMD    3
  34.     "list",
  35. #define    LIST_CMD    4
  36.     "cwd",
  37. #define    CWD_CMD        5
  38.     "dele",
  39. #define    DELE_CMD    6
  40.     "name",
  41. #define    NAME_CMD    7
  42.     "quit",
  43. #define    QUIT_CMD    8
  44.     "retr",
  45. #define    RETR_CMD    9
  46.     "stor",
  47. #define    STOR_CMD    10
  48.     "port",
  49. #define    PORT_CMD    11
  50.     "nlst",
  51. #define    NLST_CMD    12
  52.     "pwd",
  53. #define    PWD_CMD        13
  54.     "xpwd",            /* For compatibility with 4.2BSD */
  55. #define    XPWD_CMD    14
  56.     "mkd ",
  57. #define    MKD_CMD        15
  58.     "xmkd",            /* For compatibility with 4.2BSD */
  59. #define    XMKD_CMD    16
  60.     "xrmd",            /* For compatibility with 4.2BSD */
  61. #define    XRMD_CMD    17
  62.     "rmd ",
  63. #define    RMD_CMD        18
  64.     "stru",
  65. #define    STRU_CMD    19
  66.     "mode",
  67. #define    MODE_CMD    20
  68.     NULLCHAR
  69. };
  70.  
  71. /* Response messages */
  72. static char banner[] = "220 %s FTP version %s ready at %s\r\n";
  73. static char badcmd[] = "500 Unknown command\r\n";
  74. static char unsupp[] = "500 Unsupported command or option\r\n";
  75. static char givepass[] = "331 Enter PASS command\r\n";
  76. static char logged[] = "230 Logged in\r\n";
  77. static char typeok[] = "200 Type %s OK\r\n";
  78. static char only8[] = "501 Only logical bytesize 8 supported\r\n";
  79. static char deleok[] = "250 File deleted\r\n";
  80. static char mkdok[] = "200 MKD ok\r\n";
  81. static char delefail[] = "550 Delete failed: %s\r\n";
  82. static char pwdmsg[] = "257 \"%s\" is current directory\r\n";
  83. static char badtype[] = "501 Unknown type \"%s\"\r\n";
  84. static char badport[] = "501 Bad port syntax\r\n";
  85. static char unimp[] = "502 Command not yet implemented\r\n";
  86. static char bye[] = "221 Goodbye!\r\n";
  87. static char nodir[] = "553 Can't read directory \"%s\": %s\r\n";
  88. static char cantopen[] = "550 Can't read file \"%s\": %s\r\n";
  89. static char sending[] = "150 Opening data connection for %s %s\r\n";
  90. static char cantmake[] = "553 Can't create \"%s\": %s\r\n";
  91. static char writerr[] = "552 Write error: %s\r\n";
  92. static char portok[] = "200 Port command okay\r\n";
  93. static char rxok[] = "226 File received OK\r\n";
  94. static char txok[] = "226 File sent OK\r\n";
  95. static char noperm[] = "550 Permission denied\r\n";
  96. static char noconn[] = "425 Data connection reset\r\n";
  97. static char notlog[] = "530 Please log in with USER and PASS\r\n";
  98. static char okay[] = "200 Ok\r\n";
  99.  
  100. static int Sftp = -1;    /* Prototype socket for service */
  101.  
  102. /* Start up FTP service */
  103. int
  104. ftpstart(argc,argv,p)
  105. int argc;
  106. char *argv[];
  107. void *p;
  108. {
  109.     struct sockaddr_in lsocket;
  110.     int s;
  111.  
  112.     if(Sftp != -1){
  113.         /* Already running! */
  114.         freeargs(argc,argv);
  115.         return 0;
  116.     }
  117.     psignal(Curproc,0);    /* Don't keep the parser waiting */
  118.     chname(Curproc,"FTP listener");
  119.  
  120.     lsocket.sin_family = AF_INET;
  121.     lsocket.sin_addr.s_addr = Ip_addr;
  122.     if(argc < 2)
  123.         lsocket.sin_port = IPPORT_FTP;
  124.     else
  125.         lsocket.sin_port = atoi(argv[1]);
  126.  
  127.     freeargs(argc,argv);
  128.     Sftp = socket(AF_INET,SOCK_STREAM,0);
  129.     bind(Sftp,(char *)&lsocket,sizeof(lsocket));
  130.     listen(Sftp,1);
  131.     for(;;){
  132.         if((s = accept(Sftp,NULLCHAR,(int *)NULL)) == -1)
  133.             break;    /* Service is shutting down */
  134.  
  135.         /* Spawn a server */
  136.         newproc("ftpserv",2048,ftpserv,s,NULL,NULL);
  137.     }
  138.     return 0;
  139. }
  140. static void
  141. ftpserv(s,unused,p)
  142. int s;    /* Socket with user connection */
  143. void *unused;
  144. void *p;
  145. {
  146.     struct ftpserv ftp;
  147.     char **cmdp,buf[512],*arg,*cp,*cp1,*file,*mode;
  148.     long t;
  149.     int cnt,i;
  150.     struct sockaddr_in socket;
  151.  
  152.     memset((char *)&ftp,0,sizeof(ftp));    /* Start with clear slate */
  153.     ftp.data = -1;
  154.  
  155.     sockowner(s,Curproc);        /* We own it now */
  156.     ftp.control = s;
  157.     /* Set default data port */
  158.     i = SOCKSIZE;
  159.     getpeername(s,(char *)&socket,&i);
  160.     socket.sin_port = IPPORT_FTPD;
  161.     ASSIGN(ftp.port,socket);
  162.  
  163.     log(s,"open FTP");
  164.     time(&t);
  165.     cp = ctime(&t);
  166.     if((cp1 = strchr(cp,'\n')) != NULLCHAR)
  167.         *cp1 = '\0';
  168.     usprintf(s,banner,Hostname,Version,cp);
  169. loop:    if((cnt = recvline(s,buf,sizeof(buf))) == -1){
  170.         /* He closed on us */
  171.         goto finish;
  172.     }
  173.     if(cnt == 0){
  174.         /* Can't be a legal FTP command */
  175.         usprintf(ftp.control,badcmd);
  176.         goto loop;
  177.     }    
  178.     rip(buf);
  179. #ifdef    UNIX
  180.     /* Translate first word to lower case */
  181.     for(cp = buf;*cp != ' ' && *cp != '\0';cp++)
  182.         *cp = tolower(*cp);
  183. #else
  184.     /* Translate entire buffer to lower case */
  185.     for(cp = buf;*cp != '\0';cp++)
  186.         *cp = tolower(*cp);
  187. #endif
  188.     /* Find command in table; if not present, return syntax error */
  189.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  190.         if(strncmp(*cmdp,buf,strlen(*cmdp)) == 0)
  191.             break;
  192.     if(*cmdp == NULLCHAR){
  193.         usprintf(ftp.control,badcmd);
  194.         goto loop;
  195.     }
  196.     /* Allow only USER, PASS and QUIT before logging in */
  197.     if(ftp.cd == NULLCHAR || ftp.path == NULLCHAR){
  198.         switch(cmdp-commands){
  199.         case USER_CMD:
  200.         case PASS_CMD:
  201.         case QUIT_CMD:
  202.             break;
  203.         default:
  204.             usprintf(ftp.control,notlog);
  205.             goto loop;
  206.         }
  207.     }
  208.     arg = &buf[strlen(*cmdp)];
  209.     while(*arg == ' ')
  210.         arg++;
  211.  
  212.     /* Execute specific command */
  213.     switch(cmdp-commands){
  214.     case USER_CMD:
  215.         free(ftp.username);
  216.         if((ftp.username = strdup(arg)) == NULLCHAR){
  217.             shutdown(ftp.control,1);
  218.             goto finish;
  219.         }
  220.         usprintf(ftp.control,givepass);
  221.         break;
  222.     case TYPE_CMD:
  223.         switch(arg[0]){
  224.         case 'A':
  225.         case 'a':    /* Ascii */
  226.             ftp.type = ASCII_TYPE;
  227.             usprintf(ftp.control,typeok,arg);
  228.             break;
  229.         case 'l':
  230.         case 'L':
  231.             while(*arg != ' ' && *arg != '\0')
  232.                 arg++;
  233.             if(*arg == '\0' || *++arg != '8'){
  234.                 usprintf(ftp.control,only8);
  235.                 break;
  236.             }
  237.             ftp.type = LOGICAL_TYPE;
  238.             ftp.logbsize = 8;
  239.             usprintf(ftp.control,typeok,arg);
  240.             break;
  241.         case 'B':
  242.         case 'b':    /* Binary */
  243.         case 'I':
  244.         case 'i':    /* Image */
  245.             ftp.type = IMAGE_TYPE;
  246.             usprintf(ftp.control,typeok,arg);
  247.             break;
  248.         default:    /* Invalid */
  249.             usprintf(ftp.control,badtype,arg);
  250.             break;
  251.         }
  252.         break;
  253.     case QUIT_CMD:
  254.         usprintf(ftp.control,bye);
  255.         goto finish;
  256.     case RETR_CMD:
  257.         file = pathname(ftp.cd,arg);
  258.         switch(ftp.type){
  259.         case IMAGE_TYPE:
  260.         case LOGICAL_TYPE:
  261.             mode = READ_BINARY;
  262.             break;
  263.         case ASCII_TYPE:
  264.             mode = READ_TEXT;
  265.             break;
  266.         }
  267.         if(!permcheck(&ftp,RETR_CMD,file)){
  268.              usprintf(ftp.control,noperm);
  269.         } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  270.             usprintf(ftp.control,cantopen,file,sys_errlist[errno]);
  271.         } else {
  272.             log(ftp.control,"RETR %s",file);
  273.             sendit(&ftp,"RETR",file);
  274.         }
  275.         free(file);
  276.         break;
  277.     case STOR_CMD:
  278.         file = pathname(ftp.cd,arg);
  279.         switch(ftp.type){
  280.         case IMAGE_TYPE:
  281.         case LOGICAL_TYPE:
  282.             mode = WRITE_BINARY;
  283.             break;
  284.         case ASCII_TYPE:
  285.             mode = WRITE_TEXT;
  286.             break;
  287.         }
  288.         if(!permcheck(&ftp,STOR_CMD,file)){
  289.              usprintf(ftp.control,noperm);
  290.         } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  291.             usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  292.         } else {
  293.             log(ftp.control,"STOR %s",file);
  294.             recvit(&ftp,"STOR",file);
  295.         }
  296.         free(file);
  297.         break;
  298.     case PORT_CMD:
  299.         if(pport(&ftp.port,arg) == -1){
  300.             usprintf(ftp.control,badport);
  301.         } else {
  302.             usprintf(ftp.control,portok);
  303.         }
  304.         break;
  305. #ifndef CPM
  306.     case LIST_CMD:
  307.         file = pathname(ftp.cd,arg);
  308.         if(!permcheck(&ftp,RETR_CMD,file)){
  309.              usprintf(ftp.control,noperm);
  310.         } else if((ftp.fp = dir(file,1)) == NULLFILE){
  311.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  312.         } else {
  313.             sendit(&ftp,"LIST",file);
  314.         }
  315.         free(file);
  316.         break;
  317.     case NLST_CMD:
  318.         file = pathname(ftp.cd,arg);
  319.         if(!permcheck(&ftp,RETR_CMD,file)){
  320.              usprintf(ftp.control,noperm);
  321.         } else if((ftp.fp = dir(file,0)) == NULLFILE){
  322.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  323.         } else {
  324.             sendit(&ftp,"NLST",file);
  325.         }
  326.         free(file);
  327.         break;
  328.     case CWD_CMD:
  329.         file = pathname(ftp.cd,arg);
  330.         if(!permcheck(&ftp,RETR_CMD,file)){
  331.              usprintf(ftp.control,noperm);
  332.             free(file);
  333. #ifdef    MSDOS
  334.         /* Don'tcha just LOVE %%$#@!! MS-DOS? */
  335.         } else if(strcmp(file,"/") == 0 || access(file,0) == 0){
  336. #else
  337.         } else if(access(file,0) == 0){    /* See if it exists */
  338. #endif
  339.             /* Succeeded, record in control block */
  340.             free(ftp.cd);
  341.             ftp.cd = file;
  342.             usprintf(ftp.control,pwdmsg,file);
  343.         } else {
  344.             /* Failed, don't change anything */
  345.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  346.             free(file);
  347.         }
  348.         break;
  349.     case XPWD_CMD:
  350.     case PWD_CMD:
  351.         usprintf(ftp.control,pwdmsg,ftp.cd);
  352.         break;
  353. #else
  354.     case LIST_CMD:
  355.     case NLST_CMD:
  356.     case CWD_CMD:
  357.     case XPWD_CMD:
  358.     case PWD_CMD:
  359. #endif
  360.     case ACCT_CMD:        
  361.         usprintf(ftp.control,unimp);
  362.         break;
  363.     case DELE_CMD:
  364.         file = pathname(ftp.cd,arg);
  365.         if(!permcheck(&ftp,DELE_CMD,file)){
  366.              usprintf(ftp.control,noperm);
  367.         } else if(unlink(file) == 0){
  368.             usprintf(ftp.control,deleok);
  369.         } else {
  370.             usprintf(ftp.control,delefail,sys_errlist[errno]);
  371.         }
  372.         free(file);
  373.         break;
  374.     case PASS_CMD:
  375.         ftplogin(&ftp,arg);            
  376.         break;
  377. #ifndef    CPM
  378.     case XMKD_CMD:
  379.     case MKD_CMD:
  380.         file = pathname(ftp.cd,arg);
  381.         if(!permcheck(&ftp,MKD_CMD,file)){
  382.             usprintf(ftp.control,noperm);
  383. #ifdef    UNIX
  384.         } else if(mkdir(file,0777) == 0){
  385. #else
  386.         } else if(mkdir(file) == 0){
  387. #endif
  388.             usprintf(ftp.control,mkdok);
  389.         } else {
  390.             usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  391.         }
  392.         free(file);
  393.         break;
  394.     case XRMD_CMD:
  395.     case RMD_CMD:
  396.         file = pathname(ftp.cd,arg);
  397.         if(!permcheck(&ftp,RMD_CMD,file)){
  398.              usprintf(ftp.control,noperm);
  399.         } else if(rmdir(file) == 0){
  400.             usprintf(ftp.control,deleok);
  401.         } else {
  402.             usprintf(ftp.control,delefail,sys_errlist[errno]);
  403.         }
  404.         free(file);
  405.         break;
  406.     case STRU_CMD:
  407.         if(tolower(arg[0]) != 'f')
  408.             usprintf(ftp.control,unsupp);
  409.         else
  410.             usprintf(ftp.control,okay);
  411.         break;
  412.     case MODE_CMD:
  413.         if(tolower(arg[0]) != 's')
  414.             usprintf(ftp.control,unsupp);
  415.         else
  416.             usprintf(ftp.control,okay);
  417.         break;
  418.     }
  419. #endif
  420.     goto loop;
  421. finish:
  422.     log(ftp.control,"close FTP");
  423.     /* Clean up */
  424.     close_s(ftp.control);
  425.     if(ftp.data != -1)
  426.         close_s(ftp.data);
  427.     if(ftp.fp != NULLFILE)
  428.         fclose(ftp.fp);
  429.     free(ftp.username);
  430.     free(ftp.path);
  431.     free(ftp.cd);
  432. }
  433.  
  434. /* Shut down FTP server */
  435. int
  436. ftp0(argc,argv,p)
  437. int argc;
  438. char *argv[];
  439. void *p;
  440. {
  441.     close_s(Sftp);
  442.     Sftp = -1;
  443.     return 0;
  444. }
  445. static
  446. int
  447. pport(sock,arg)
  448. struct sockaddr_in *sock;
  449. char *arg;
  450. {
  451.     int32 n;
  452.     int i;
  453.  
  454.     n = 0;
  455.     for(i=0;i<4;i++){
  456.         n = atoi(arg) + (n << 8);
  457.         if((arg = strchr(arg,',')) == NULLCHAR)
  458.             return -1;
  459.         arg++;
  460.     }
  461.     sock->sin_addr.s_addr = n;
  462.     n = atoi(arg);
  463.     if((arg = strchr(arg,',')) == NULLCHAR)
  464.         return -1;
  465.     arg++;
  466.     n = atoi(arg) + (n << 8);
  467.     sock->sin_port = n;
  468.     return 0;
  469. }
  470. /* Attempt to log in the user whose name is in ftp->username and password
  471.  * in pass
  472.  */
  473. static void
  474. ftplogin(ftp,pass)
  475. struct ftpserv *ftp;
  476. char *pass;
  477. {
  478.     char buf[80],*cp,*cp1;
  479.     FILE *fp;
  480.     int anony = 0;
  481.  
  482.     if((fp = fopen(Userfile,READ_TEXT)) == NULLFILE){
  483.         /* Userfile doesn't exist */
  484.         usprintf(ftp->control,noperm);
  485.         return;
  486.     }
  487.     while(fgets(buf,sizeof(buf),fp),!feof(fp)){
  488.         if(buf[0] == '#')
  489.             continue;    /* Comment */
  490.         if((cp = strchr(buf,' ')) == NULLCHAR)
  491.             /* Bogus entry */
  492.             continue;
  493.         *cp++ = '\0';        /* Now points to password */
  494.         if(strcmp(ftp->username,buf) == 0)
  495.             break;        /* Found user name */
  496.     }
  497.     if(feof(fp)){
  498.         /* User name not found in file */
  499.         fclose(fp);
  500.         usprintf(ftp->control,noperm);
  501.         return;
  502.     }
  503.     fclose(fp);
  504.     /* Look for space after password field in file */
  505.     if((cp1 = strchr(cp,' ')) == NULLCHAR){
  506.         /* Invalid file entry */
  507.         usprintf(ftp->control,noperm);
  508.         return;
  509.     }
  510.     *cp1++ = '\0';    /* Now points to path field */
  511.     if(strcmp(cp,"*") == 0)
  512.         anony = 1;    /* User ID is password-free */
  513.     if(!anony && strcmp(cp,pass) != 0){
  514.         /* Password required, but wrong one given */
  515.         usprintf(ftp->control,noperm);
  516.         return;
  517.     }
  518.     if((cp = strchr(cp1,' ')) == NULLCHAR){
  519.         /* Permission field missing */
  520.         usprintf(ftp->control,noperm);
  521.         return;
  522.     }
  523.     *cp++ = '\0';    /* now points to permission field */
  524.  
  525.     /* Set up current directory and path prefix */
  526.     ftp->cd = strdup(cp1);
  527.     ftp->path = strdup(cp1);
  528.     
  529.     /* And finally set the permission bits */
  530.     ftp->perms = atoi(cp);
  531.  
  532.     usprintf(ftp->control,logged);
  533.     if(!anony)
  534.         log(ftp->control,"%s logged in",ftp->username);
  535.     else
  536.         log(ftp->control,"%s logged in, ID %s",ftp->username,pass);
  537. }        
  538.  
  539. #ifdef    MSDOS
  540. /* Illegal characters in a DOS filename */
  541. static char badchars[] = "\"[]:|<>+=;,";
  542. #endif
  543.  
  544. /* Return 1 if the file operation is allowed, 0 otherwise */
  545. static int
  546. permcheck(ftp,op,file)
  547. struct ftpserv *ftp;
  548. int op;
  549. char *file;
  550. {
  551.     char *cp;
  552.  
  553.     if(file == NULLCHAR || ftp->path == NULLCHAR)
  554.         return 0;    /* Probably hasn't logged in yet */
  555. #ifdef    MSDOS
  556.     /* Check for characters illegal in MS-DOS file names */
  557.     for(cp = badchars;*cp != '\0';cp++){
  558.         if(strchr(file,*cp) != NULLCHAR)
  559.             return 0;    
  560.     }
  561. #endif
  562. #if    (defined(AMIGA) || defined(MAC))
  563. #else
  564.     /* The target file must be under the user's allowed search path */
  565.     if(strncmp(file,ftp->path,strlen(ftp->path)) != 0)
  566.         return 0;
  567. #endif
  568.  
  569.     switch(op){
  570.     case RETR_CMD:
  571.         /* User must have permission to read files */
  572.         if(ftp->perms & FTP_READ)
  573.             return 1;
  574.         return 0;
  575.     case DELE_CMD:
  576.     case RMD_CMD:
  577.         /* User must have permission to (over)write files */
  578.         if(ftp->perms & FTP_WRITE)
  579.             return 1;
  580.         return 0;
  581.     case STOR_CMD:
  582.     case MKD_CMD:
  583.         /* User must have permission to (over)write files, or permission
  584.          * to create them if the file doesn't already exist
  585.          */
  586.         if(ftp->perms & FTP_WRITE)
  587.             return 1;
  588.         if(access(file,2) == -1 && (ftp->perms & FTP_CREATE))
  589.             return 1;
  590.         return 0;
  591.     }
  592.     return 0;    /* "can't happen" -- keep lint happy */
  593. }
  594. static int
  595. sendit(ftp,command,file)
  596. struct ftpserv *ftp;
  597. char *command;
  598. char *file;
  599. {
  600.     long total;
  601.     struct sockaddr_in dport;
  602.  
  603.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  604.     dport.sin_family = AF_INET;
  605.     dport.sin_addr.s_addr = Ip_addr;
  606.     dport.sin_port = IPPORT_FTPD;
  607.     bind(ftp->data,(char *)&dport,SOCKSIZE);
  608.     usprintf(ftp->control,sending,command,file);
  609.     if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
  610.         fclose(ftp->fp);
  611.         ftp->fp = NULLFILE;
  612.         close_s(ftp->data);
  613.         ftp->data = -1;
  614.         usprintf(ftp->control,noconn);
  615.         return -1;
  616.     }
  617.     /* Do the actual transfer */
  618.     total = sendfile(ftp->fp,ftp->data,ftp->type);
  619.  
  620.     if(total == -1){
  621.         /* An error occurred on the data connection */
  622.         usprintf(ftp->control,noconn);
  623.         shutdown(ftp->data,2);    /* Blow away data connection */
  624.     } else {
  625.         usprintf(ftp->control,txok);
  626.     }
  627.     fclose(ftp->fp);
  628.     ftp->fp = NULLFILE;
  629.     close_s(ftp->data);
  630.     ftp->data = -1;
  631.     if(total == -1)
  632.         return -1;
  633.     else
  634.         return 0;
  635. }
  636. static int
  637. recvit(ftp,command,file)
  638. struct ftpserv *ftp;
  639. char *command;
  640. char *file;
  641. {
  642.     struct sockaddr_in dport;
  643.     long total;
  644.  
  645.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  646.     dport.sin_family = AF_INET;
  647.     dport.sin_addr.s_addr = Ip_addr;
  648.     dport.sin_port = IPPORT_FTPD;
  649.     bind(ftp->data,(char *)&dport,SOCKSIZE);
  650.     usprintf(ftp->control,sending,command,file);
  651.     if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
  652.         fclose(ftp->fp);
  653.         ftp->fp = NULLFILE;
  654.         close_s(ftp->data);
  655.         ftp->data = -1;
  656.         usprintf(ftp->control,noconn);
  657.         return -1;
  658.     }
  659.     total = recvfile(ftp->fp,ftp->data,ftp->type);
  660.  
  661. #ifdef    CPM
  662.     if(ftp->type == ASCII_TYPE)
  663.         fputc(CTLZ,ftp->fp);
  664. #endif
  665.     if(total == -1) {
  666.         /* An error occurred while writing the file */
  667.         usprintf(ftp->control,writerr,sys_errlist[errno]);
  668.         shutdown(ftp->data,2);    /* Blow it away */
  669.     } else {
  670.         usprintf(ftp->control,rxok);
  671.         close_s(ftp->data);
  672.     }
  673.     ftp->data = -1;
  674.     fclose(ftp->fp);
  675.     ftp->fp = NULLFILE;
  676.     if(total == -1)
  677.         return -1;
  678.     else
  679.         return 0;
  680. }
  681.